package Agents;

import java.awt.Color;

import Helpers.Common;
import Helpers.EnumBehaviour;
import Model.SimModel;
import Param.Constants;
import sim.engine.SimState;
import sim.util.Bag;
import sim.util.Int2D;

public class Human extends Entity 
{
	public Human(SimModel m, Int2D position, EnumBehaviour b) {
		super(m, position);
		// TODO initialisation de l'age
		virus = new Virus(this);
		this.behaviour = b;
		this.age = Common.getRandom(0, Constants.HUMAN_EXPECTANCY / 2);
		this.life = Constants.HUMAN_MAX_LIFE;

		// Initialisation de la couleur de l'agent
		switch (this.behaviour) {
			case ALONE:
				this.paint = new Color(16, 78, 139);
				break;
			case GATHER:
				this.paint = Color.CYAN;
				break;
			case FLEE:
				this.paint = new Color(0, 206, 209);
				break;
		}
	}

	private static final long serialVersionUID = 1L;

	Virus virus;
	int age;

	EnumBehaviour behaviour;

	/**
	 * Algorithme général
	 */
	@Override
	public void step(SimState state) 
	{
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		if (isInfected()) {
			this.paint = Color.yellow;
			//System.out.println("Humain contaminé");
		}

		// On supprime les éventuels rectangles
		Common.removeRectangles(this.model.yard, x, y);
		Bag elementsNextTo = this.detectAdjacent();
		// Ne détecte rien d'intéressant sur les cases adjacentes
		if (!elementsNextTo.isEmpty()) {
			// Détecte dans la zone de perception
			Zombie z = Common.getWeakestZombie(elementsNextTo);
			if(z!=null){ //Si zombie � proximit�
				this.attack(z);
				// Colorer les cases pour le combat
				displayRectAttack();
				survive();
				return;
			}
		}
		// Comportement normal s'il n'y a pas de zombie adjacent
		switch (this.behaviour) {
		case ALONE:
			// ne fait rien
			break;
		case FLEE:
			flee();
			break;
		case GATHER:
			gather();
			break;
		default:
			break;
		}
		
		virus.step();
		getOld();
		survive();
		
		// Recuperation des points de vie
		life = Constants.HUMAN_MAX_LIFE;
	}

	private void getOld() {
		age++;
		if(age > model.getHumanExpectancy()){
			if(life <= 0) {
				// Ne rien faire, gere dans survive()
			}
			else {
				die();
			}
		}
	}

	private void flee() {
		Bag elements = new Bag();
		Int2D pos = new Int2D(-1,-1);
		int barx = 0, bary = 0;
		elements = detectInPerception();
		for (int i=0;i<elements.size();i++){
			if (elements.get(i) instanceof Zombie){
				pos = ((Zombie)elements.get(i)).getPos();
				barx += position.x - pos.x;
				bary += position.y - pos.y;
			}
		}
		if(barx != 0 && bary != 0){
			pos = new Int2D(position.x + barx, position.y + bary);
			Movement mov = getAllowedMovement(pos);
			move(mov.position);
		}
	}

	private void gather() {
		Bag elements = new Bag();
		Int2D pos = new Int2D(-1,-1);
		int barx = 0, bary = 0;
		elements = detectInPerception();
		for (Object o : elements){
			if (o instanceof Human){
				pos = ((Human)o).getPos();
				barx += pos.x - position.x;
				bary += pos.y - position.y;
			}
		}
		pos = new Int2D(position.x + barx, position.y + bary);
		Movement mov = getAllowedMovement(pos);
		move(mov.position);
	}

	private void turnIntoCorpse() {
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		virus.contaminate();
		model.addCorpse(position, virus);
		model.deleteHuman(this);
		model.yard.remove(this);
		Common.removeRectangles(this.model.yard, x, y);
		stoppable.stop();
	}

	public void turnIntoZombie() {
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		model.addZombie(position);
		model.deleteHuman(this);
		model.yard.remove(this);
		Common.removeRectangles(this.model.yard, x, y);
		stoppable.stop();
	}


	public EnumBehaviour getBehaviour() {
		return behaviour;
	}

	@Override
	protected void die() {
		turnIntoCorpse();
		int x = this.getPos().x;
		int y = this.getPos().y;
		
		Common.removeRectangles(this.model.yard, x, y);
	}

	public Virus getVirus()
	{
		return this.virus;
	}

	public int getAge(){
		return age;
	}

	public boolean isInfected() {
		return this.virus.isActive();
	}
}
